package com.wtf.generator.dao;

import com.baomidou.dynamic.datasource.spring.boot.autoconfigure.DataSourceProperty;
import com.baomidou.mybatisplus.annotation.DbType;
import com.mysql.jdbc.Driver;
import com.wtf.generator.enums.CommonErrorEnum;
import com.wtf.generator.exception.CommonException;
import com.wtf.generator.model.dto.DsAddDTO;
import com.zaxxer.hikari.HikariDataSource;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.stereotype.Component;

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.util.List;
import java.util.Map;
import java.util.Properties;

/**
 * date: 2022/6/18 10:59
 * @author linhuanyou
 * @email 496558736@qq.com
 * @version 1.0
 */
@Component
public abstract class AbstractGeneratorDao implements GeneratorDao{

    @Autowired
    private JdbcTemplate jdbcTemplate;

    @Override
    public <T> T queryForObject(String sql, Class<T> requiredType) {
        return jdbcTemplate.queryForObject(sql,requiredType);
    }

    @Override
    public List<Map<String, Object>> queryForList(String sql) {
        return jdbcTemplate.queryForList(sql);
    }

    @Override
    public <T> List<T> queryForList(String sql, Class<T> elementType) {
        return jdbcTemplate.queryForList(sql,elementType);
    }

    @Override
    public Map<String, Object> queryForMap(String sql) {
        return jdbcTemplate.queryForMap(sql);
    }


    @Override
    public Connection openConnection(DsAddDTO dsDbDTO) throws CommonException {
        Connection connection = null;
        try {
            Class.forName(getDriver());
            Properties props = new Properties();
            props.put("remarksReporting", "true");
            props.put("user", dsDbDTO.getUsername());
            props.put("password", dsDbDTO.getPassword());
            connection = DriverManager.getConnection(
                    getUrl(dsDbDTO.getHost(), dsDbDTO.getPort(), dsDbDTO.getDbName()), props);
        } catch (ClassNotFoundException e) {
            String errorMsg = "连接创建失败，找不到相关驱动类(" + e.getMessage() + ")";
            throw new CommonException(CommonErrorEnum.OPEN_CONNECTION_EXCEPTION.getErrCode(), errorMsg, e);
        } catch (Exception e) {
            throw new CommonException(CommonErrorEnum.OPEN_CONNECTION_EXCEPTION, e);
        }
        return connection;
    }

    protected abstract String getDriver();

    protected abstract String getUrl(String host,Integer port,String dbName);

    @Override
    public void closeConnection(Connection connection) throws CommonException {
        if (connection != null) {
            try {
                connection.close();
                connection = null;
            } catch (SQLException e) {
                throw new CommonException(CommonErrorEnum.CLOSE_CONNECTION_EXCEPTION.getErrCode(), e.getMessage(), e);
            }
        }
    }

    public DataSourceProperty getDataSourceProperty(DsAddDTO dsDbDTO){
        DataSourceProperty dataSourceProperty = new DataSourceProperty();
        dataSourceProperty.setPoolName(dsDbDTO.getDs());
        dataSourceProperty.setType(HikariDataSource.class);
        dataSourceProperty.setUrl(getUrl(dsDbDTO.getHost(), dsDbDTO.getPort(), dsDbDTO.getDbName()));
        dataSourceProperty.setDriverClassName(getDriver());
        dataSourceProperty.setUsername(dsDbDTO.getUsername());
        dataSourceProperty.setPassword(dsDbDTO.getPassword());
        return dataSourceProperty;
    }

    public Properties getProperties(String jdbcUrl, DbType dbType) throws Exception {
        Properties properties = null;
        switch (dbType){
            case MYSQL:
                Driver mysqlDriver = new Driver();
                properties = mysqlDriver.parseURL(jdbcUrl,null);
                break;
            case POSTGRE_SQL:
                Properties pgProperties = org.postgresql.Driver.parseURL(jdbcUrl, null);
                properties = new Properties();
                properties.put("HOST", pgProperties.getProperty("PGHOST"));
                properties.put("PORT", pgProperties.getProperty("PGPORT"));
                properties.put("DBNAME", pgProperties.getProperty("PGDBNAME"));
                break;
            default:
                break;
        }
        return properties;
    }
}
